#include "communicationlogger.h"
#include <QFile>
#include <QTextStream>

CommunicationLogger::CommunicationLogger(QObject *parent)
    : QAbstractListModel(parent)
{
}

void CommunicationLogger::clear()
{
    if (m_logs.isEmpty())
        return;
    
    beginResetModel();
    m_logs.clear();
    endResetModel();
}

void CommunicationLogger::saveToFile(const QString &filePath)
{
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        logError(QString("Failed to open file for writing: %1").arg(filePath));
        return;
    }
    
    QTextStream out(&file);
    out.setEncoding(QStringConverter::Utf8);
    
    for (const LogEntry &entry : m_logs) {
        QString directionStr;
        switch (entry.direction) {
        case TX:
            directionStr = "TX";
            break;
        case RX:
            directionStr = "RX";
            break;
        case ERROR:
            directionStr = "ERR";
            break;
        case INFO:
            directionStr = "INFO";
            break;
        }
        
        out << entry.timestamp.toString("yyyy-MM-dd hh:mm:ss.zzz") << " "
            << directionStr << " "
            << entry.message << "\n";
    }
    
    file.close();
}

void CommunicationLogger::logFrame(LogDirection direction, const QByteArray &data)
{
    // Auto-trim if we've reached the limit
    if (m_logs.count() >= MAX_LOG_ENTRIES) {
        beginRemoveRows(QModelIndex(), 0, 0);
        m_logs.removeFirst();
        endRemoveRows();
    }
    
    LogEntry entry;
    entry.timestamp = QDateTime::currentDateTime();
    entry.direction = direction;
    entry.message = formatFrame(data);
    
    beginInsertRows(QModelIndex(), m_logs.count(), m_logs.count());
    m_logs.append(entry);
    endInsertRows();
}

void CommunicationLogger::logError(const QString &error)
{
    // Auto-trim if we've reached the limit
    if (m_logs.count() >= MAX_LOG_ENTRIES) {
        beginRemoveRows(QModelIndex(), 0, 0);
        m_logs.removeFirst();
        endRemoveRows();
    }
    
    LogEntry entry;
    entry.timestamp = QDateTime::currentDateTime();
    entry.direction = ERROR;
    entry.message = error;
    
    beginInsertRows(QModelIndex(), m_logs.count(), m_logs.count());
    m_logs.append(entry);
    endInsertRows();
}

void CommunicationLogger::logInfo(const QString &info)
{
    // Auto-trim if we've reached the limit
    if (m_logs.count() >= MAX_LOG_ENTRIES) {
        beginRemoveRows(QModelIndex(), 0, 0);
        m_logs.removeFirst();
        endRemoveRows();
    }
    
    LogEntry entry;
    entry.timestamp = QDateTime::currentDateTime();
    entry.direction = INFO;
    entry.message = info;
    
    beginInsertRows(QModelIndex(), m_logs.count(), m_logs.count());
    m_logs.append(entry);
    endInsertRows();
}

int CommunicationLogger::rowCount(const QModelIndex &parent) const
{
    if (parent.isValid())
        return 0;
    return m_logs.count();
}

QVariant CommunicationLogger::data(const QModelIndex &index, int role) const
{
    if (!index.isValid() || index.row() >= m_logs.count())
        return QVariant();
    
    const LogEntry &entry = m_logs.at(index.row());
    
    switch (role) {
    case TimestampRole:
        return entry.timestamp.toString("hh:mm:ss.zzz");
    case DirectionRole:
        if (entry.direction == TX) return "TX";
        if (entry.direction == RX) return "RX";
        if (entry.direction == ERROR) return "ERR";
        if (entry.direction == INFO) return "INFO";
        return "UNKNOWN";
    case MessageRole:
        return entry.message;
    default:
        return QVariant();
    }
}

QHash<int, QByteArray> CommunicationLogger::roleNames() const
{
    QHash<int, QByteArray> roles;
    roles[TimestampRole] = "timestamp";
    roles[DirectionRole] = "direction";
    roles[MessageRole] = "message";
    return roles;
}

QString CommunicationLogger::formatFrame(const QByteArray &data)
{
    QString result;
    for (int i = 0; i < data.size(); ++i) {
        if (i > 0)
            result += " ";
        result += QString("%1").arg(static_cast<quint8>(data[i]), 2, 16, QChar('0')).toUpper();
    }
    return result;
}
